﻿using SqlScriptVault.Commands;
using SqlScriptVault.Model;
using SqlScriptVault.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SqlScriptVault.ViewModel
{
    class MainWindowViewModel
    {
        private const string NewScriptVaultFilename = "New script vault";

        private readonly IFileService _fileService;
        private readonly IMessageDisplayService _messageDisplayService;

        private ScriptVaultState _currentState;
        private string _currentFilename;

        public MainWindowViewModel(IFileService fileService, IMessageDisplayService messageDisplayService)
        {
            _fileService = fileService;
            _messageDisplayService = messageDisplayService;

            ChangeState(ScriptVaultState.New, NewScriptVaultFilename, false);

            EventService.Instance.Subscribe(EventService.ScriptVaultChangedEvent, ScriptVaultChanged);
        }

        public MainWindowViewModel()
            : this(new FileService(), new MessageDisplayService())
        {
        }

        ~MainWindowViewModel()
        {
            EventService.Instance.Unsubscribe(EventService.ScriptVaultChangedEvent);
        }

        public RelayCommand NewFileCommand
        {
            get { return new RelayCommand(param => NewFile()); }
        }

        public RelayCommand OpenFileCommand
        {
            get { return new RelayCommand(param => OpenFile()); }
        }

        public RelayCommand SaveFileCommand
        {
            get { return new RelayCommand(param => SaveFile()); }
        }

        public RelayCommand ExecuteCommand
        {
            get { return new RelayCommand(param => Execute()); }
        }

        public RelayCommand OpenHistoryCommand
        {
            get { return new RelayCommand(param => OpenHistory()); }
        }

        public RelayCommand OpenConnectionManagerCommand
        {
            get { return new RelayCommand(param => OpenConnectionManager()); }
        }

        private void NewFile()
        {
            object result = EventService.Instance.Publish(EventService.NewEvent, null);

            if (result is bool && (bool) result)
            {
                ChangeState(ScriptVaultState.New, NewScriptVaultFilename, false);
            }
        }

        private void OpenFile()
        {
            string fileName = _fileService.OpenFileDialog("*.sqlvault", "SQL Script Vault files (.sqlvault)|*.sqlvault");

            if (fileName == null)
            {
                return;
            }

            if (!_fileService.Exists(fileName))
            {
                _messageDisplayService.ShowErrorMessage("File not found!");
                return;
            }

            object result = EventService.Instance.Publish(EventService.LoadEvent, fileName);

            if (result is bool && (bool)result)
            {
                ChangeState(ScriptVaultState.Opened, fileName, false);
            }
        }

        private bool SaveFile()
        {
            string fileName = string.Empty;

            switch (_currentState)
            {
                case ScriptVaultState.New:
                case ScriptVaultState.Unsaved:
                    fileName = _fileService.SaveFileDialog("*.sqlvault", "SQL Script Vault files (.sqlvault)|*.sqlvault");

                    if (fileName == null)
                    {
                        return false;
                    }

                    break;

                case ScriptVaultState.Opened:
                case ScriptVaultState.Saved:
                    fileName = _currentFilename;
                    break;
            }

            if (fileName == string.Empty)
            {
                return false;
            }

            EventService.Instance.Publish(EventService.SaveEvent, fileName);

            ChangeState(ScriptVaultState.Saved, fileName, false);

            return true;
        }

        private void Execute()
        {
            if (_currentState != ScriptVaultState.Saved && !SaveFile())
            {
                return;
            }            

            EventService.Instance.Publish(EventService.ExecuteEvent, null);
        }

        private void OpenHistory()
        {
            EventService.Instance.Publish(EventService.OpenHistoryEvent, null);
        }

        private void OpenConnectionManager()
        {
            _messageDisplayService.OpenConnectionManager();
        }

        private object ScriptVaultChanged(object obj)
        {
            switch (_currentState)
            {
                case ScriptVaultState.New:
                    ChangeState(ScriptVaultState.New, _currentFilename, true);
                    break;
                case ScriptVaultState.Opened:
                    ChangeState(ScriptVaultState.Opened, _currentFilename, true);
                    break;
                case ScriptVaultState.Saved:
                case ScriptVaultState.Unsaved:
                    ChangeState(ScriptVaultState.Unsaved, _currentFilename, true);
                    break;
            }

            return null;
        }

        private void ChangeState(ScriptVaultState state, string fileName, bool changed)
        {
            _currentState = state;
            _currentFilename = fileName;

            EventService.Instance.Publish(EventService.TitleChangedEvent, string.Format("{0}{1}", _currentFilename, changed ? " *" : string.Empty));
        }
    }
}
